/**
 * 
 */
package net.looker.monitor.crawler;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Date;
import java.util.logging.Logger;

import net.looker.config.ConfigManager;
import net.looker.data.Media;
import net.looker.util.Html;
import net.looker.util.URLUtils;
import net.looker.work.CallBack;

/**
 * 文件下载器
 * 下载新闻中出现的图片，附件等。。
 * @author solosky
 */

public class MediaCrawler extends Crawler
{
	/**
	 * 文件对象，用于保存文件信息
	 */
	private volatile Media media;
	
	/**
	 * 文件保存根目录
	 */
	private String mediaSaveRoot;
	
	/**
	 * 构造函数
	 * @param url
	 * @throws MalformedURLException 
	 */
	public MediaCrawler(Media m) throws MalformedURLException
	{
		super(m.getUrl());
		media = m;
		mediaSaveRoot = ConfigManager.getInstance().getLookerConfig().get("media.saveDir")+'/';
	}
	
	/**
	 * 构造函数
	 * @param m
	 * @param cb
	 * @throws MalformedURLException
	 */
	public MediaCrawler(Media m,CallBack cb) throws MalformedURLException
	{
		super(m.getUrl(),cb);
		media = m;
		mediaSaveRoot = ConfigManager.getInstance().getLookerConfig().get("media.saveDir")+'/';
	}
	
	/* (non-Javadoc)
	 * @see net.looker.monitor.crawler.Crawler#getCrawled()
	 */
	@Override
	public Object getCrawled()
	{
		return media;
	}
	/* (non-Javadoc)
	 * @see net.looker.site.category.crawler.Crawler#crawl()
	 */
	@Override
	public void crawl() throws IOException, CrawlerException
	{
		//尝试建立连接，如果错误马上返回
		try {
			openURL();
		} catch (CrawlerException e) {
			media.MarkError();
			throw new CrawlerException(e.getMessage());
		}
		
		//检查返回的文件类型，如果是网页文件返回
		String type = getHeader("Content-Type");
		int    end  = -1;
		//返回的类型如 text/html; charset=gb2312，这里需要提取text/html
		if (type!=null)
		{
			end  = type.indexOf(';');
			if (end!=-1)
				type = type.substring(0, end);
			if (type.equals("text/html"))
			{
				markError();
				media.MarkError();
				Logger.getLogger("looker").warning("下载文件类型错误:"+media.getUrl()+"|"+type);
				throw new CrawlerException("下载文件类型错误:"+media.getUrl()+"|"+type);
			}
		}
		
		//保存文件
		 saveFile();
		//标记抓取完成
		markFinished();		
	}
	
	/**
	 * 保存文件
	 * @throws IOException 
	 * @throws CrawlerException 
	 */
	private void saveFile() throws IOException, CrawlerException
	{
		//建立文件开始保存下载的文件
		File saveFile = getSaveFile(getSaveDir());
		if (saveFile==null)
		{
			markError();
			media.MarkError();
			throw new CrawlerException("文件无法写入："+saveFile.getAbsolutePath());
		}
		
		//打开文件，开始读取服务器文件内容
		//获取网络输入流
	    BufferedInputStream bis = new BufferedInputStream(conn.getInputStream());
	    //建立文件
	    FileOutputStream fos = new FileOutputStream(saveFile);
	    //保存文件
	    int size = 0;
	    byte[] buf = new byte[255];
	    
	    while ( (size = bis.read(buf)) != -1) 
	      fos.write(buf, 0, size);
	    
	    fos.close();
	    bis.close();
		    
	    //填写文件一些信息
		media.setSize((int)saveFile.length());
		
		//检查文件
		checkSavedFile();		
	}
	
	
	/**
	 * 得到保存文件对象
	 * @return File
	 */
	private File getSaveFile(File saveDir)
	{
		if (saveDir==null)
			return null;
		String saveName = getSaveName();
		//建立文件
		File saveFile = new File(saveDir.getPath()+'/'+saveName.toString());
		if (!saveFile.exists() && !saveFile.isDirectory())
			return saveFile;
		else 
			return null;
	}
	
	/**
	 * 返回保存文件目录
	 * 文件保存规则：
	 * media.saveDir/domainName/4位数年-2位数月份
	 * @return File
	 */
	private File getSaveDir()
	{
		StringBuffer saveDirName = new StringBuffer();
		saveDirName.append(URLUtils.domain(media.getUrl()));
		saveDirName.append('/');
		//www.domain.com
		//检查域名文件夹是否存在
		File saveDir = new File(mediaSaveRoot+saveDirName.toString());
		if(!saveDir.exists())
			saveDir.mkdir();
		
		Calendar cl = Calendar.getInstance();
		saveDirName.append(cl.get(Calendar.YEAR));
		saveDirName.append("-");
		saveDirName.append(cl.get(Calendar.MONTH));
		
		//www.domain.comm/2009-6/
		//检查目录是否存在，如果不存在，则创建
		saveDir = new File(mediaSaveRoot+saveDirName.toString());
		if(!saveDir.exists())
			saveDir.mkdir();
		
		saveDirName.append('/'+media.getType().name());
		//www.domain.com/2009-6/i/
		saveDir = new File(mediaSaveRoot+saveDirName.toString());
		if(!saveDir.exists())
			saveDir.mkdir();
		media.setSaveDir(saveDirName.toString());
		
		return saveDir;
	}
	
	/**
	 * 返回文件名
	 * 文件保存规则：
	 * 时间戳_原文件名.扩展名
	 */
	private String getSaveName()
	{
		StringBuffer saveName = new StringBuffer();
		//时间戳
		saveName.append(media.getDate().getTime());
		saveName.append("_");
		//文件名
		//检查返回的头部信息是否有Content-Disposition: attachment; filename="TPtpl.rar"
		//如果有，以此文件名代替原来的文件名
		String tmpName = getHeader("Content-Disposition");
		if(tmpName!=null)
		{
			String newName = null;
			int start = tmpName.lastIndexOf("=");
			if (tmpName.charAt(start+1)=='"' || tmpName.charAt(start+1)=='\'')
				newName = tmpName.substring(start+2, tmpName.length()-1);
			else
				newName = tmpName.substring(start+1);
			saveName.append(newName);
			//更新保存的文件名
			//NOTE:这里数据库里保存的是没有加时间前缀的文件名
			media.setName(newName);
		}
		else
			saveName.append(media.getName());
		
		return saveName.toString();
	}
	
	/**
	 * 检查下载的文件
	 * 如果是图片，检查下载的图片小于设定的最小图片大小
	 * 如果小于设定的图片大小，删除指定文件，并标记错误
	 * @throws CrawlerException 
	 */
	
	public void checkSavedFile() throws CrawlerException
	{
		if (media.getType()==Media.ETYPE.i)
		{
			int imgMinSize = Integer.parseInt(ConfigManager.getInstance().getLookerConfig().get("media.imageMinSize"));
			if (imgMinSize>media.getSize())
			{
				File image = new File(mediaSaveRoot+'/'+media.getSaveDir()+'/'+media.getDate().getTime()+'_'+media.getName()); 
				if(image.exists())
				{
					image.delete();
					media.MarkError();
					throw new CrawlerException("文件下载器:图片小于指定的大小放弃->"+media.getUrl());	
				}
			}
		}
	}
	/**
	 * 
	 * @param args
	 * @throws IOException
	 * @throws CrawlerException
	 */
	
	public static void main(String[] args) throws IOException, CrawlerException
	{
		Media m = new Media("http://localhost/phpMyAdmin/themes/original/img/logo_right.png","sssssssss", "sss");
		MediaCrawler fc = new MediaCrawler(m);
		fc.crawl();
		System.out.println(m.getName());
		System.out.println(m.getSize());
	}
}
